#include "Calculator.h"

extern Calculator calculator;

void warnning()
{
    P3_6 = 0;
    delay(0x7f);
    P3_6 = 1;
}


void init_timer()
{
    TMOD = 0x11; 
    EA = 1;  
    ET0 = 1; 
    ET1 = 1; 
    TH0 = 0xff;
    TL0 = 0x00;
    TH1 = 0xff;
    TL1 = 0x00;
}


void init()
{
    init_timer();

    calculator.left_op = 0;
    calculator.right_op = 0;
    calculator.result = 0;
    calculator.op = INVALID_OP;
    calculator.op_count = 0;

    TR0 = 1;
    TR1 = 1;
}



static void time1_interrupt(void) interrupt 3
{
    TH1 = 0xff;
    TL1 = 0x00;

    if ( calculator.is_overflow ) {
        led_print_hex(0xffffffff);
    } else {
        if ( calculator.is_calculated ) {
            led_print_dec(calculator.result);
        } else if ( calculator.op_count == 0 ) {
            led_print_dec(calculator.left_op);
        } else {
            led_print_dec(calculator.right_op);
        }
    }

    led_scan();
}

static int convert(int scan_code)
{
    int key;

    switch ( scan_code ) {
        case 12 :
            key = '+';
        break;
        case 8 :
            key = '-';
        break;
        case 4 :
            key = '*';
        break;
        case 0 :
            key = '/';
        break;
        case 13 :
            key = 7;
        break;
        case 9 :
            key = 8;
        break;
        case 5 :
            key = 9;
        break;
        case 1 :
            key = 0;
        break;
        case 14 :
            key = 4;
        break;
        case 10 :
            key = 5;
        break;
        case 6 :
            key = 6;
        break;
        case 2 :
            key = '.';
        break;
        case 15 :
            key = 1;
        break;
        case 11 :
            key = 2;
        break;
        case 7 :
            key = 3;
        break;
        case 3 :
            key = '=';
        break;
    }

    return key;
}


void calculate()
{

    switch ( calculator.op ) {
        case '+' :
            calculator.result = calculator.left_op + calculator.right_op;
        break;
        case '-' :
            calculator.result = calculator.left_op - calculator.right_op;
        break;
        case '*' :
            calculator.result = calculator.left_op * calculator.right_op;
        break;
        case '/' :
            calculator.result = calculator.left_op / calculator.right_op;
        break;
        case INVALID_OP :
            warnning();
        break;
    }

    calculator.is_calculated = 1;

    if ( calculator.result > 99999999 ) {
        calculator.is_overflow = 1;
        return;
    }
    calculator.left_op = calculator.result;
}


void get_op(int key)
{
    if ( key == '=' ) {
        if ( calculator.op_count == 0 ) {
            calculator.result = calculator.left_op;
        } else {
            calculate();
        }
        return;
    }

    calculator.is_calculated = 0;
    switch ( key ) {
        case '+' :
            if ( calculator.op != INVALID_OP ) {
                calculate();
            }
            ++calculator.op_count;
            calculator.op = '+';
            calculator.right_op = 0;
        break;
        case '-' :
            if ( calculator.op != INVALID_OP ) {
                calculate();
            }
            ++calculator.op_count;
            calculator.op = '-';
            calculator.right_op = 0;
        break;
        case '*' :
            if ( calculator.op != INVALID_OP ) {
                calculate();
            }
            ++calculator.op_count;
            calculator.op = '*';
            calculator.right_op = 0;
        break;
        case '/' :
            if ( calculator.op != INVALID_OP ) {
                calculate();
            }
            ++calculator.op_count;
            calculator.op = '/';
            calculator.right_op = 0;
        break;
        default :
            if ( calculator.op_count == 0 ) {
                calculator.left_op = calculator.left_op * 10 + key;
            } else if ( calculator.op_count > 0 ) {
                calculator.right_op = calculator.right_op * 10 + key;
            }
        break;
    }
}


static void time0_interrupt(void) interrupt 1
{
    int scan_code = key_scan();
    int key;

    TR0 = 0;

    TH0 = 0x00;
    TL0 = 0x00;


    if ( scan_code == 0xff ) {
        TR0 = 1;
        return;
    }

    key = convert(scan_code);
    get_op(key);

    warnning();

    TR0 = 1;
}
